/**
 * FileFind - ftp/shares indexing and search php engine
 * Module: agent-java
 * Description: Agent written in java language
 * Copyright (c) 2003-2010 Rage Steel, www.gt2.ru
 * ----------------------------------------------
 * $Id$
 */
package ru.ffind.agent.model;

import ru.ffind.common.model.Directory;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 *
 * Storage for directory listing
 * To be used by FileScanner thread and database sync thread
 *
 * @author Rage Steel
 *
 */
abstract public class AbstractListingStorage implements ListingStorage {
	
	/**
	 * Path to directory mapping
	 * for root directory path is /
	 */
	private final ConcurrentMap<String, Directory> listing = new ConcurrentHashMap<String, Directory>();
	
	/**
	 *  Count of files/directories, including roots
	 */
	private final AtomicLong filesCount = new AtomicLong(0);
	
	/* (non-Javadoc)
	 * @see ru.ffind.agent.io.IListingStorage#put(java.lang.String, ru.ffind.agent.model.Directory)
	 */
	@Override
	public void put(String absolutePath, Directory contents) {
		if (isScanComplete()) {
			throw new IllegalStateException("Unable to add to ListingStorage after completition of scanning");
		}
		
//		System.out.println("Adding directory: " + absolutePath);
		
		Directory existing = listing.putIfAbsent(absolutePath, contents);
		
		if (null != existing) {
			// FIXME use logging
			throw new RuntimeException("Duplication of listing: " + absolutePath);
		}
		
		filesCount.addAndGet(contents.getCount());
	}
	
//	/*
//	 * (non-Javadoc)
//	 * @see ru.ffind.agent.model.ListingStorage#get(java.lang.String)
//	 */
//	@Override
//	public Directory get(String absolutePath) {
//		return listing.get(absolutePath);
//	}
	
	/* (non-Javadoc)
	 * @see ru.ffind.agent.io.IListingStorage#getAndRemove(java.lang.String)
	 */
	@Override
	public Directory getAndRemove(String absolutePath) {
		// FIXME add waiting for dir
		Directory result = listing.remove(absolutePath);
		if (null != result) {
			filesCount.addAndGet(-result.getCount());
		}
		return result;
	}
	
	/* (non-Javadoc)
	 * @see ru.ffind.agent.model.ListingStorage#getAndRemoveWithWait(java.lang.String, long)
	 */
	@Override
	public Directory getAndRemoveWithWait(String absolutePath, long retryTimeout) {
		Directory directory;
		while (null == (directory = getAndRemove(absolutePath))) {
			if (isScanComplete()) {
				return null;
			}
			try {
				Thread.sleep(retryTimeout);
			} catch (InterruptedException e) {
				// IGNORED
			}
		}
		return directory;
	}
	
	/* (non-Javadoc)
	 * @see ru.ffind.agent.model.ListingStorage#getFilesCount()
	 */
	@Override
	public long getFilesCount() {
		return filesCount.get();
	}
}
